<template lang="pug">
.puzzle
  .puzzle-materials
    .material-header
      .iconfont.icon-back(@click="clearFilter")
      .header-search
        el-input(placeholder="请输入关键词搜索" prefix-icon="el-icon-search" v-model="searchString" @change="changeSearch" clearable)
    .material-selects
      el-select(size="small" placeholder="全部业态" v-model="styleId" @change="changeSearch" clearable)
        el-option(v-for="item in stylesList", :key="item.styleId", :label="item.styleName", :value="item.styleId")
      el-select(size="small" placeholder="分类" v-model="classificationId" @change="changeSearch" clearable)
        el-option(v-for="item in cateList", :key="item.id", :label="item.title", :value="item.id")
    .material-list(ref="materialList")
      .material-list-bd
        .material-item(v-for="item in materialList")
          .material-item-body
            .material-item-img(
              :style="{ 'background-image': `url(${item.picImg})` }"
              draggable="true"
              @dragstart="handleDragStart($event, item)"
            )
            .material-item-bd
              .material-item-name {{item.materialName}}
              .material-item-price {{item.lowPrice}}~{{item.highPrice}}
              .material-item-company {{item.companyName}}
  .puzzle-canvas
    main.sketch-main
      //- 操作栏
      
      .sketch-main-handle
        .sketch-main-handle-input
          el-input(placeholder="电子拼板的名字" v-model="sketch.title")
        .main-handles
          .main-handles-item(@click="undoFun", :class="{'disabled': !_history.undo.length}")
            .iconfont.icon-undo
            .index-handle-item-label 撤销
          .main-handles-item(@click="redoFun", :class="{'disabled': !_history.redo.length}")
            .iconfont.icon-restore
            .index-handle-item-label 恢复
          .main-handles-item(@click.stop="showDropdown")
            .iconfont.icon-canvas
            .index-handle-item-label 画布
            .dropdown(v-show="dropdownShow" @click.stop="() => {}")
              p(@click="resetSketch") 重置画布
              p(@click="clearSketch") 清空画布
          .main-handles-item(@click="temporarySave")
            .iconfont.icon-save
            .index-handle-item-label 保存
      puzzle-handles(@changeRandom="changeRandom")
      .sketch-main-container
        .sketch-main-wrapper
          .sketch-canvas(ref="canvasWrap" @drop="drop($event,'item')" @dragover="allowDrop($event)")
            canvas#canvas
          .sketch-matrix3d(v-if="matrix.show")
            image-transform(
              :width="canvasWidth"
              :height="canvasHeight"
              :imgSrc="matrix.img"
              :points="matrix.points"
              ref="matrix3d"
            )
</template>

<script>
import puzzleHandles from './components/handles'
import imageTransform from '@/components/ImageTransform'
import fabric from '@/utils/fabric'
import uuid from 'uuid/v4'
import { FileUpload, submitPuzzle, getPuzzleDetail, getPuzzleTemplateDetail, getMaterialList, getStyleList, getCategoryList } from 'api'
import { mapActions, mapState } from 'vuex'
export default {
  name: 'puzzleEdit',
  data () {
    return {
      canvasBaseWidth: 1440,
      canvasBaseHeight: 800,
      canvasWidth: 944,
      canvasHeight: 617,
      searchString: '',
      sketch: {
        title: '',
        cont: null,
        preview: ''
      },
      styleId: '',
      classificationId: '',
      searchString: '',
      saveing: false, // 是否正在保存
      reseting: false, // 是否正在重置画布
      dropdownShow: false,
      sideShow: true,
      parentCurrentNav: 0,
      currentItem: {},
      saveType: '',
      materialList: [],
      page: 1,
      pageSize: 12,
      stylesList: [],
      cateList: []
    }
  },
  computed: {
    ...mapState({
      matrix: state => state.sketch.matrix,
      sketchGoods: state => state.sketch.sketchGoods,
      _history: state => state.sketch.history,
      requestStatus: state => state.modal.requestStatus.status
    })
  },
  components: {
    imageTransform,
    puzzleHandles
  },
  methods: {
    ...mapActions([
      'changeMatrix',
      'updateHistory',
      'changeSketchGoods',
      'clearHistory',
      'changeMaterialText',
      'changeVueColor',
      'changeSkuDetail',
      'changeRandomCate',
      'showConfirmModal',
      'rePlayHistory'
    ]),
    clearFilter () {
      this.$router.back()
    },
    async getStyles () {
      try {
        const { ResultSet } = await this.$axios.post(getStyleList)
        this.stylesList = ResultSet.userData.styleList
      } catch (err) {
        console.log(err)
        this.$message.error(err.message || err.ResultSet.errors)
      }
    },
    async getCategoryList () {
      try {
        const { ResultSet } = await this.$axios.post(getCategoryList)
        this.cateList = ResultSet.userData.result
      } catch (err) {
        console.log(err)
        this.$message.error(err.message || err.ResultSet.errors)
      }
    },
    changeSearch () {
      this.page = 1
      this.getMaterialList()
    },
    undoFun () { // 后退
      if (this.matrix.show) return
      if (this._history.undo.length) this.rePlayHistory({ playStack: 'undo', saveStack: 'redo' })
    },
    redoFun () { // 前进
      if (this.matrix.show) return
      if (this._history.redo.length) this.rePlayHistory({ playStack: 'redo', saveStack: 'undo' })
    },
    showDropdown () {
      this.dropdownShow = !this.dropdownShow
    },
    handleDragStart (e, item) {
      let event = document.createEvent('Event')
      event.initEvent('mydragstart', true, true)
      event['data'] = {
        url: item.picImg,
        ...item
      }
      let include = document.elementFromPoint(e.pageX, e.pageY)
      // 派发事件
      include.dispatchEvent(event)
    },
    async resetSketch () {
      try {
        const confirmed = await this.showConfirmModal({
          title: '重置画布',
          paragraph: '确定要重置该画布吗？',
          confirmButtonText: '确定',
          cancelButtonText: '取消'
        })
        if (confirmed !== 1) return
        if (this.$route.params.id) {
          if (this.reseting) return
          this.reseting = true
          if (this.$route.query.from && this.$route.query.from === 'default') {
            const { ResultSet } = await this.$axios.post(getPuzzleTemplateDetail, { id: this.$route.params.id })
            window.canvas.loadFromJSON(JSON.parse(ResultSet.userData.cont), this.updateHistory)
            this.changeSketchGoods({ type: 'reload', list: ResultSet.userData.materials })
          } else {
            const { ResultSet } = await this.$axios.post(getPuzzleDetail, { id: this.$route.params.id })
            window.canvas.loadFromJSON(JSON.parse(ResultSet.userData.cont), this.updateHistory)
            this.changeSketchGoods({ type: 'reload', list: ResultSet.userData.materials })
          }
        } else {
          window.canvas.clear()
          this.changeSketchGoods({type: 'clear'})
        }
      } catch (err) {
        console.log(err)
        this.$message.error(err.message || err.ResultSet.errors)
      } finally {
        setTimeout(() => {
          this.reseting = false
        }, 2000)
      }
    },
    async clearSketch () {
      const confirmed = await this.showConfirmModal({
        title: '清空画布',
        paragraph: '确定要清空该画布吗？',
        confirmButtonText: '确定',
        cancelButtonText: '取消'
      })
      if (confirmed !== 1) return
      window.canvas.clear()
      this.updateHistory()
      this.changeSketchGoods({type: 'clear'})
    },
    temporarySave () {
      if (!this.sketch.title) {
        this.$message.error('请先输入电子拼版名字！')
        return
      }
      if (!this.$route.params.id) {
        this.exit()
      } else {
        if (this.saveing || !canvas._objects.length) return
        this.saveing = true
        const blob = this.dataURLtoBlob(canvas.toDataURL({ format: 'jpg', width: 1440, height: 800 }))
        this.saveType = 'temporarySave'
        this.FileUpload(blob)
      }
      // this.up.addFile(blob)
      // this.up.start()
    },
    async initSketch (id) {
      try {
        if (this.$route.query.from && this.$route.query.from === 'default') {
          const { ResultSet } = await this.$axios.post(getPuzzleTemplateDetail, { id: this.$route.params.id })
          this.sketch = ResultSet.userData
          this.changeSketchGoods({ type: 'reload', list: ResultSet.userData.materials })
          canvas.loadFromJSON(JSON.parse(ResultSet.userData.cont), this.updateHistory)
        } else {
          const { ResultSet } = await this.$axios.post(getPuzzleDetail, { id: this.$route.params.id })
          this.sketch = ResultSet.userData
          this.changeSketchGoods({ type: 'reload', list: ResultSet.userData.materials })
          canvas.loadFromJSON(JSON.parse(ResultSet.userData.cont), this.updateHistory)
        }
      } catch (err) {
        this.$message.error(err.message || err.ResultSet.errors)
      }
    },
    async exit (name) {
      if (this.matrix.show) {
        this.$message.error('操作失败，正在执行变形操作')
        return
      }
      this.from = name
      if (canvas._objects.length) {
        const confirmed = await this.showConfirmModal({
          title: '退出确认',
          paragraph: `要在退出之前存储对搭配方案“${this.sketch.title}”的更改吗？`,
          confirmButtonText: '存储并退出',
          isSaveBtn: true
        })
        this.changeSkuDetail({ show: false, id: null })
        this.changeRandomCate()
        if (confirmed === 1) {
          if (!this.sketch.title) {
            this.$message.error('请先输入电子拼版名字！')
            return
          }
          this.loading = this.$loading({text: ''})
          const blob = this.dataURLtoBlob(canvas.toDataURL({ format: 'jpg', width: 840, height: 594 }))
          this.saveType = 'exit'
          this.FileUpload(blob)
        } else if (confirmed === 0) {
          canvas.clear().renderAll()
          if (name === 'sketchList') {
            this.$refs.sketchList.routerPush()
          } else {
            this.$router.back()
            this.loading && this.loading.close()
          }
        } else {
          this.loading && this.loading.close()
        }
      } else {
        this.changeSkuDetail({ show: false, id: null })
        canvas.clear().renderAll()
        if (name === 'sketchList') this.$refs.sketchList.routerPush()
        else this.$router.back()
      }
    },
    async FileUpload (Blob) {
      try {
        const Blob2ImageFileForWXBrowser = new window.File([Blob], `${(new Date).getTime()}.png`, {type: Blob.type})
        let formData = new FormData()
        formData.append('Filedata', Blob2ImageFileForWXBrowser)
        formData.append("applicationId", 4)
        const { ResultSet } = await this.$axios.post(FileUpload, { formData: formData, isUpload: true }, { headers:{ "Content-Type": "multipart/form-data" } })
        if (this.saveType === 'exit') {
          this.sketch.preview = ResultSet.Result[0].fileUrl
          this.sketch.fileManage = ResultSet.Result[0]
          await this.save() // 上传成功后提交保存
          this.$router.back()
          this.clearHistory()
        } else if (this.saveType === 'temporarySave') {
          this.sketch.preview = ResultSet.Result[0].fileUrl
          this.sketch.fileManage = ResultSet.Result[0]
          await this.save()
          this.$router.replace({
            name: this.$route.name,
            params: { id: this.caseId },
            // 保存后，需要刷新我的案例列表，在我的案例内，会监听temporarySave值的变化，从而进行更新
            query: { type: 'edit', ...this.$route.query, temporarySave: new Date().getTime() }
          })
        }
        // this.sketch.preview = ResultSet.Result[0].fileUrl
        // this.sketch.fileManage = ResultSet.Result[0]
        // this.save()
      } catch (err) {
        console.log(err)
      }
    },
    async save () {
      try {
        if (this.$route.params.id && this.$route.query.type === 'edit') this.form.id = this.$route.params.id // 如果属于编辑才提交ID
        this.sketch.cont = JSON.stringify(canvas.toJSON(['mid', 'uid']))
        await this.$axios.post(submitPuzzle, { ...this.sketch, materials: this.sketchGoods })
        // this.caseId = data.id
        // if (this.from === 'sketchList') this.$refs.sketchList.routerPush()
      } catch (err) {
        console.log(err)
        this.$message.error(err.msg)
      } finally {
        this.saveing = false
        this.loading && this.loading.close()
      }
    },
    dataURLtoBlob (dataUrl) {
      let arr = dataUrl.split(',')
      let mime = arr[0].match(/:(.*?);/)[1]
      let bstr = atob(arr[1])
      let n = bstr.length
      let u8arr = new Uint8Array(n)
      while (n--) u8arr[n] = bstr.charCodeAt(n)
      console.log(new Blob([u8arr], { type: mime }))
      return new Blob([u8arr], { type: mime })
    },
    // temporarySave () {
    //   if (this.saveing || !canvas._objects.length) return
    //   this.saveing = true
    //   const blob = this.dataURLtoBlob(canvas.toDataURL({ format: 'jpg', width: 1440, height: 800 }))
    //   this.up.addFile(blob)
    //   this.up.start()
    //   this.saveType = 'temporarySave'
    // },
    resizeCanvas () {},
    allowDrop (ev) {
      ev.preventDefault()
    },
    changeRandom () {},
    drop (e) {
      e.preventDefault()
      // 容器的位置信息
      let containerRect = this.$refs.canvasWrap.getBoundingClientRect()
      // 拖拽目标的数据
      let data = e.data || this.currentItem
      let uid = uuid()
      let type = data.type
      let url = data.url
      fabric.Image.fromURL(url, (img) => {
        img.set({
          mid: data.id,
          // goods_key: data.key,
          // 以鼠标位置为中心点
          left: e.pageX - 100 - containerRect.left,
          top: e.pageY - 100 - containerRect.top,
          uid
        })
        img.scaleToWidth(200)
        canvas.add(img)
        canvas.setActiveObject(img)
        canvas.renderAll()
        this.changeSketchGoods({ type: 'set', good: { mid: data.id, uid } })
        this.updateHistory()
      }, {
        crossOrigin: 'anonymous'
      })
    },
    async getMaterialList () {
      try {
        this.materialList = []
        let query = {
          currentPage: this.page,
          pageLines: this.pageSize
        }
        if (this.searchString) query.searchString = this.searchString
        if (this.styleId) query.styleId = this.styleId
        if (this.classificationId) query.classificationId = this.classificationId
        const { ResultSet } = await this.$axios.post(getMaterialList, { ...query })
        this.isLoading = false
        if (!ResultSet.userData.result.length) this.isLoaded = true
        else this.isLoaded = false
        this.materialList = ResultSet.userData.result
        if (ResultSet.userData.result.length) this.page += 1
      } catch (err) {
        console.log(err)
        this.$message.error(err.message || err.ResultSet.errors)
      }
    },
    async loadMore () {
      try {
        if (this.isLoading || this.isLoaded) return
        this.isLoading = true
        let query = {
          currentPage: this.page,
          pageLines: this.pageSize
        }
        if (this.searchString) query.searchString = this.searchString
        if (this.styleId) query.styleId = this.styleId
        if (this.classificationId) query.classificationId = this.classificationId
        const { ResultSet } = await this.$axios.post(getMaterialList, { ...query })
        this.page += 1
        if (!ResultSet.userData.result.length) this.isLoaded = true
        this.materialList.push(...ResultSet.userData.result)
        this.$nextTick(() => {
          this.isLoading = false
        })
      } catch (err) {
        console.log(err)
        this.$message.error(err.message || err.ResultSet.errors)
        this.isLoading = false
      }
    }
  },
  mounted () {
    let scrollEle = this.$refs.materialList
    scrollEle.addEventListener('scroll', e => {
      const { scrollHeight, scrollTop, offsetHeight } = scrollEle
      if (scrollHeight - scrollTop - offsetHeight < 100) this.loadMore()
    })
    window.onbeforeunload = (e) => {
      if (canvas._objects.length) return ''
    }
    window.addEventListener('mydragstart', (e) => {
      this.currentItem = e.data
    })
    const scale = this.sideShow ? 0.75 : 1
    // 初始化canvas并把canvas注入到全局
    window.canvas = new fabric.Canvas('canvas', {
      preserveObjectStacking: true,
      uniScaleTransform: false,
      width: this.canvasWidth,
      height: this.canvasHeight,
      selectionColor: 'rgba(0,0,0,.2)',
      selectionBorderColor: '#000',
      selectionLineWidth: 1,
      selectionDashArray: [10, 10],
      backgroundColor: '#ffffff'
    })
  
    // 重写添加功能，实现变形时拦截添加行为
    let that = this
    window.canvas.add = function () {
      if (that.matrix.show) {
        that.$message('请先取消变形')
        return
      }
  
      let obj = arguments[0] // obj->当前要添加的对象
      obj.set({
        minScaleLimit: 50 / obj.width // 限制对象最小缩放比例
      })
  
      this._objects.push.apply(this._objects, arguments)
      if (this._onObjectAdded) {
        for (var i = 0, length = arguments.length; i < length; i++) {
          this._onObjectAdded(arguments[i])
        }
      }
      this.renderOnAddRemove && this.requestRenderAll()
      return this
    }
    window.canvas.setActiveObject = function (object, e) {
      if (that.matrix.show) return
      var currentActives = this.getActiveObjects()
      this._setActiveObject(object, e)
      this._fireSelectionEvents(currentActives, e)
      return this
    }
  
    // this.resizeCanvas()
    this.updateHistory()
    canvas.on('selection:created', (e) => {
      return false
    })
    canvas.on('object:modified', (e) => { // 修改
      this.updateHistory()
    })
    canvas.on('touch:gesture', (e) => {
      e.target.set({ lockRotation: true })
    })
    // canvas中的内容获取焦点
    canvas.on('selection:updated', (e) => {
      if (e.target.text) {
        this.changeMaterialText({ isText: true })
        this.changeVueColor({ color: e.target.fill })
      } else {
        this.changeMaterialText({ isText: false })
      }
    })
    // canvas中的内容失去焦点
    canvas.on('selection:cleared', (e) => {
      this.changeMaterialText({ isText: false })
    })
    // canvas中创建新内容
    canvas.on('selection:created', (e) => {
      if (e.target.text) {
        this.changeMaterialText({ isText: true })
        this.changeVueColor({ color: e.target.fill })
      } else {
        this.changeMaterialText({ isText: false })
      }
    })
    canvas.on('object:moving', (e) => {
      let img = e.target
      let maxTop = -(img.height * img.scaleY / 2)
      let maxBottom = canvas.height - (img.height * img.scaleY / 2)
      let maxLeft = -(img.width * img.scaleX / 2)
      let maxRight = canvas.width - (img.width * img.scaleX / 2)
      if (img.top < 0 && img.top <= maxTop) img.top = maxTop
      if (img.top > 0 && img.top >= maxBottom) img.top = maxBottom
      if (img.left < 0 && img.left <= maxLeft) img.left = maxLeft
      if (img.left > 0 && img.left >= maxRight) img.left = maxRight
    })
    canvas.wrapperEl.addEventListener('touchend', () => {
      let obj = canvas.getActiveObject()
      if (obj) obj.set({ lockRotation: obj.lockScalingX })
    })
    if (this.$route.query.add) this.addImage()
    
  },
  beforeRouteEnter (to, from, next) {
    next(vm => {
      vm.getMaterialList()
      vm.getStyles()
      vm.getCategoryList()
      if (to.params.id) vm.initSketch(to.params.id)
    })
  },
  beforeRouteLeave (to, from, next) {
    this.clearHistory()
    next()
  },
  beforeRouteUpdate (to, from, next) {
    next()
    if (to.params.id && to.params.id !== from.params.id) {
      this.initSketch(to.params.id)
      // 再创作时，关闭变形模式
      this.changeMatrix({points: {}, img: '', show: false})
    }
  },
} 
</script>

<style type="text/css" lang="scss">
.header-search {
  .el-input__inner {
    border-color: #8B8EAB;
    color: #fff;
    background-color: transparent !important;
  }
}
.material-selects {
  .el-input__inner {
    // border-color: #8B8EAB;
    color: #fff;
    background-color: transparent !important;
    border: none;
  }
}
</style>

<style lang="scss" scoped>
.puzzle {
  height: 100%;
  display: flex;
}
.puzzle-materials {
  width: 592px;
  padding: 8px 0;
  background: #3B3E5C;
  box-shadow: 0px 4px 0px #F3F3F4;
  border-radius: 10px 10px 0 0;
}
.puzzle-canvas {
  flex: 1;
}
.material-header {
  display: flex;
  align-items: center;
  padding: 16px 40px;
  .iconfont {
    cursor: pointer;
    font-size: 24px;
    color: #B2B4C7;
    margin-right: 32px;
  }
  .header-search {
    flex: 1;
    .el-input__inner {
      background-color: transparent !important;
    }
  }
}
.material-selects {
  padding: 0 40px;
  .el-select {
    width: 100px;
    margin-right: 32px;
  }
}
.material-list {
  height: calc(100% - 122px);
  overflow-y: overlay;
  margin-top: 24px;
  padding: 0 32px;
  .material-list-bd {
    display: flex;
    flex-wrap: wrap;
  }
  .material-item {
    width: 33.333%;
    padding: 0 8px 24px;
    .material-item-body {
      width: 100%;
      height: 202px;
      background: #FFFFFF;
      border-radius: 6px;
      .material-item-img {
        width: 100%;
        height: 120px;
        border-radius: 6px 6px 0 0;
        background-position: center;
        background-repeat: no-repeat;
        background-size: cover;
      }
      .material-item-bd {
        padding: 8px;
        .material-item-name {
          font-weight: bold;
          font-size: 14px;
          line-height: 22px;
          color: #3E4373;
          overflow: hidden;
          text-overflow: ellipsis;
          white-space: nowrap;
        }
        .material-item-price {
          font-size: 12px;
          line-height: 20px;
          color: #FF2E42;
          margin-top: 2px;
        }
        .material-item-company {
          font-size: 12px;
          line-height: 20px;
          color: #8B8EAB;
          margin-top: 2px;
        }
      }
    }
  }
}
#canvas {
  border-radius: 10px;
}
.sketch-main {
  position: relative;
  width: 100%;
  height: 100%;
  background: #FAFAFE;
}
.sketch-main-container {
  padding-top: 80px;
  flex: 1;
  height: calc(100% - 81px);
  background: #FAFAFE;
  display: flex;
  align-items: center;
  justify-content: center;
}
.sketch-main-wrapper {
  width: 944px;
  height: 617px;
  // padding-bottom: 55.556%;
  background: #FFFFFF;
  border: 1px solid #F3F3F4;
  box-sizing: border-box;
  box-shadow: 0px 4px 0px #F3F3F4;
  border-radius: 10px;
  position: relative;
}
.sketch-canvas {
  position: absolute;
  left: 0;
  top: 0;
  width: 100%;
  height: 100%;
  box-shadow: 0 2px 12px 0 rgba(0,0,0,0.10);
  border-radius: 8px;
  background: #fff;
}
.sketch-matrix3d {
  position: absolute;
  left: 0;
  top: 0;
  box-shadow: 0 2px 12px 0 rgba(0,0,0,0.10);
  border-radius: 8px;
}
.sketch-main-handle {
  display: flex;
  align-items: center;
  padding-right: 40px;
  background: #fff;
  border-bottom: 1px solid #EDEDED;
}
.sketch-main-handle-input {
  padding-left: 40px;
  flex: 1;
}
.main-handles {
  display: flex;
  align-items: center;
  height: 80px;
}
.main-handles-item {
  position: relative;
  display: flex;
  align-items: center;
  margin-left: 24px;
  cursor: pointer;
  .iconfont {
    font-size: 24px;
    color: #B2B4C7;
    margin-right: 4px;
  }
  .index-handle-item-label {
    font-size: 14px;
    line-height: 22px;
    color: #64698F;
    white-space: nowrap;
  }
}
.dropdown {
  position: absolute;
  top: 30px;
  transition: all .3s;
  font-size: 14px;
  line-height: 22px;
  color: #6E6D79;
  width: 100px;
  padding: 10px 15px;
  z-index: 9;
  background: #FFFFFF;
  box-shadow: 0 2.5px 4.5px 0 rgba(0,0,0,0.10);
  border-radius: 2px;
  p {
    margin-bottom: 10px;
    &:last-child {
      margin-bottom: 0;
    }
  }
}
</style>
